Skip to content

Adjust PortableEntryPoint logic to actually handle having Wasm R2R native entrypoints#126901

Open
davidwrighton wants to merge 5 commits intodotnet:mainfrom
davidwrighton:fix_PortableEntryPoint_for_R2R_entrypoints
Open

Adjust PortableEntryPoint logic to actually handle having Wasm R2R native entrypoints#126901
davidwrighton wants to merge 5 commits intodotnet:mainfrom
davidwrighton:fix_PortableEntryPoint_for_R2R_entrypoints

Conversation

@davidwrighton
Copy link
Copy Markdown
Member

  • This includes some initial work where there is a predefined set of new thunks generated into the coreclr codebase. I expect that we'll build some sort of hardcoded list here for invokes to/from R2R code, and then have R2R supplement the list with extra cases.
  • Adjust PortableEntryPoint calling convention to match the WASM version
  • Update PortableEntryPoint::HasNativeEntryPoint to indicate that the NativeEntryPoint is the intentional target
  • Update the calls from R2R into interpreter to capture the stack argument into the TransitionBlock
  • Implement correct signature mapping for PortableEntryPoints which are FCalls
  • Update interp to managed helpers to pass a stack pointer which informs the stack walker to stop walking
  • Put the callers frame pointer into the TransitionBlock. To do so, I've added a new m_StackPointer field to the TransitionBlock
  • Make the ExecuteInterpretedMethodWtihArgs_PortableEntryPoint_Complex function into functionally being the Prestub when called from R2R.
  • Add m_StackPointer to TransitionBlock, and put the callers stack pointer in there.
  • Update helper calls in interpexec to setup the stack pointer argument correctly

…entrypoints

- This includes some initial work where there is a predefined set of new thunks generated into the coreclr codebase. I expect that we'll build some sort of hardcoded list here for invokes to/from R2R code, and then have R2R supplement the list with extra cases.
- Adjust PortableEntryPoint calling convention to match the WASM version
- Update PortableEntryPoint::HasNativeEntryPoint to indicate that the NativeEntryPoint is the intentional target
- Update the calls from R2R into interpreter to capture the stack argument into the TransitionBlock
- Implement correct signature mapping for PortableEntryPoints which are FCalls
- Update interp to managed helpers to pass a stack pointer which informs the stack walker to stop walking
- Put the callers frame pointer into the TransitionBlock. The current implementation drops it into the m_ReturnAddress field which is a bit dodgy, but we can fix this later when we actually work on the stack walker
- Make the ExecuteInterpretedMehtodWtihArgs_PortableEntryPoint_Complex function into functionally being the Prestub when called from R2R.
…inter in there.

- Update helper calls in interpexec to setup the stack pointer argument correctly
Copilot AI review requested due to automatic review settings April 14, 2026 19:02
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR’s WASM PortableEntryPoint and interpreter interop to support scenarios where R2R code calls through PortableEntryPoints that may ultimately target native entrypoints, including new thunk/signature handling and stack-walk termination plumbing.

Changes:

  • Extend signature generation and thunk tables to distinguish PortableEntryPoint calls (via a 'p' suffix) and to include InternalCall/FCall shapes.
  • Add/adjust WASM-side thunk implementations and runtime lookup/caching for R2R→interpreter and interpreter→native dispatch.
  • Update PortableEntryPoint state tracking (preferring interpreter vs native) and propagate a stack-walk termination/stack pointer through TransitionBlock and helper call paths.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs Adds optional inclusion of this in computed signatures.
src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs Switches from icall table generation to InternalCall signature collection + pregenerated signatures; writes cache as UTF-8.
src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs Generates distinct _PE call thunks for signatures ending in 'p' (PortableEntryPoint context).
src/tasks/WasmAppBuilder/coreclr/InternalCallSignatureCollector.cs New collector that scans for MethodImplAttributes.InternalCall and emits 'p'-suffixed signatures.
src/coreclr/vm/wasm/helpers.cpp Adds hardcoded R2R→interpreter thunks, PortableEntryPoint thunk cache, and signature key support for 'p' suffix.
src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp Updates generated interpreter→native thunk implementations for PortableEntryPoint calls (*_PE) and signature table entries.
src/coreclr/vm/prestub.cpp Adds PortableEntryPoint-aware interpreted execution path that can run prestub work and dispatch to compiled code.
src/coreclr/vm/precode_portable.hpp Adds PrefersInterpreterEntryPoint flag and accessors.
src/coreclr/vm/precode_portable.cpp Updates HasNativeEntryPoint/SetActualCode semantics around “prefer interpreter” state.
src/coreclr/vm/method.cpp Initializes PortableEntryPoints with an optional R2R→interpreter thunk and marks them as preferring interpreter initially.
src/coreclr/vm/jithelpers.cpp Updates WASM helper wrappers to pass stack-walk termination/TransitionBlock info into _Impl variants.
src/coreclr/vm/interpexec.h Exposes InvokeManagedMethod prototype for PortableEntryPoint prestub dispatch use.
src/coreclr/vm/interpexec.cpp Adds macros/typedefs to pass PortableEntryPoint stack/context args through helper calls; adjusts PortableEntryPoint native-entrypoint gating.
src/coreclr/vm/ilstubcache.cpp Moves SetTemporaryEntryPoint later in IL stub creation sequence.
src/coreclr/vm/gccover.cpp Updates GCFrame construction to use GC flags instead of a bool.
src/coreclr/vm/frames.h Changes GCFrame API from BOOL maybeInterior to UINT gcFlags and updates protection macros accordingly.
src/coreclr/vm/frames.cpp Implements GCFrame behavior using gcFlags and asserts flag expectations.
src/coreclr/vm/fcall.h Adjusts WASM FCALL/HCALL signatures to include hidden stack/context parameters.
src/coreclr/vm/excep.cpp Records interpreter stack pointer from TransitionBlock for WASM exception context.
src/coreclr/vm/eetwain.cpp Ensures WASM TransitionBlock has stack pointer set for funclet calls.
src/coreclr/vm/callingconvention.h Adds m_StackPointer overlay in WASM TransitionBlock.
src/coreclr/vm/callhelpers.h Introduces TERMINATE_R2R_STACK_WALK sentinel for WASM stack walking termination.
src/coreclr/runtime/portable/AllocFast.cpp Updates an internal FCALL-to-FCALL call site to pass the new WASM hidden parameters explicitly.

…ng the address of an aligned local.

- Fix the stack arg passed to R2R functions to always be 16 byte aligned
- Fix missing Call_System_Private_CoreLib_System_Environment_CallEntryPoint_I32_I32_I32_I32_I32_RetVoid thunk
Copilot AI review requested due to automatic review settings April 14, 2026 23:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the CoreCLR WASM PortableEntryPoint calling convention and thunk/signature infrastructure to support ReadyToRun (R2R) native entrypoints while preserving correct interpreter dispatch and stack-walking behavior.

Changes:

  • Extends WASM signature generation to account for PortableEntryPoint context ('p') and InternalCall/FCall signature shapes.
  • Adds R2R-to-interpreter thunk support, including capturing the caller stack pointer into TransitionBlock and using it to terminate/limit stack walking.
  • Adjusts PortableEntryPoint state management and prestub-like behavior to correctly resolve interpreter vs native (R2R) targets.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs Adds optional inclusion of this to signature mapping for instance methods.
src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs Replaces icall table generation with InternalCall signature collection and adds pregenerated signature shapes.
src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs Generates distinct call thunks for PortableEntryPoint calls (extra hidden params + stack-walk termination).
src/tasks/WasmAppBuilder/coreclr/InternalCallSignatureCollector.cs New scanner to collect InternalCall signatures for thunk generation.
src/coreclr/vm/wasm/helpers.cpp Adds R2R→interpreter thunk table/cache and updates managed calli invocation to carry PE context.
src/coreclr/vm/wasm/callhelpers-reverse.cpp Updates reverse-thunk exports and signature naming adjustments.
src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp Updates generated thunk table to include PE-aware signatures and call patterns.
src/coreclr/vm/prestub.cpp Adds PortableEntryPoint “complex” path that behaves like prestub when invoked from R2R.
src/coreclr/vm/precode_portable.hpp Adds PrefersInterpreterEntryPoint flag/accessors and updates PortableEntryPoint API surface.
src/coreclr/vm/precode_portable.cpp Updates native-entrypoint detection and allows “upgrade” from interpreter-preferred to actual code.
src/coreclr/vm/method.cpp Initializes PortableEntryPoint with an R2R→interpreter thunk when available and sets interpreter-preferred state.
src/coreclr/vm/jithelpers.cpp WASM FCALL wrappers now pass stack pointer / transition info to exception helpers.
src/coreclr/vm/interpexec.h Exposes InvokeManagedMethod for prestub/R2R dispatch paths.
src/coreclr/vm/interpexec.cpp Adjusts helper calling patterns and PortableEntryPoint selection logic; threads stack-pointer through transition blocks.
src/coreclr/vm/ilstubcache.cpp Moves SetTemporaryEntryPoint later in IL stub creation sequence.
src/coreclr/vm/gccover.cpp Updates GCFrame usage to new ctor parameterization (gcFlags).
src/coreclr/vm/frames.h Changes GCFrame API from maybeInterior to gcFlags and updates GCPROTECT macros.
src/coreclr/vm/frames.cpp Implements GCFrame gcFlags handling and enforces interior-flag expectations.
src/coreclr/vm/fcall.h Updates FCALL/HCALL macro signatures for WASM to include hidden stack/context args.
src/coreclr/vm/excep.cpp Plumbs interpreter stack pointer from TransitionBlock into exception frame context.
src/coreclr/vm/eetwain.cpp Ensures WASM transition blocks set stack pointer consistently for funclet calls.
src/coreclr/vm/callingconvention.h Extends WASM TransitionBlock to carry m_StackPointer.
src/coreclr/vm/callhelpers.h Adds TERMINATE_R2R_STACK_WALK sentinel for WASM stack-walk termination.
src/coreclr/runtime/portable/AllocFast.cpp Updates a FCALL wrapper to supply explicit hidden args under new WASM calling convention.

class PortableEntryPoint final
{
public: // static
// Returns true if the NativeEntryPoint of a given PortableEntryPoint is set to an exact target address (instead of a thunk or other auxiliary code), and that target is the provided address.
Comment on lines +56 to +58

foreach (var nestedType in type.GetNestedTypes())
ScanType(nestedType);
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 14, 2026 23:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates CoreCLR WASM PortableEntryPoint plumbing to support ReadyToRun (R2R) native entrypoints and correct calling conventions/signature handling across interpreter ↔ native transitions (including FCalls), with additional stack-walk/TransitionBlock support.

Changes:

  • Extend signature generation/mapping to support PortableEntryPoint context (p) and InternalCall (FCall) signatures; update thunk generation accordingly.
  • Add initial hardcoded R2R→interpreter PortableEntryPoint thunk set and associated lookup/caching paths; adjust prestub-style dispatch for PortableEntryPoint calls.
  • Update runtime structures/paths for WASM stack-walk termination and TransitionBlock stack pointer propagation; refactor GCFrame to use GC flag bitmasks.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/tasks/WasmAppBuilder/coreclr/SignatureMapper.cs Adds optional inclusion of this in computed signatures.
src/tasks/WasmAppBuilder/coreclr/ManagedToNativeGenerator.cs Switches from icall table generation to InternalCall signature collection; adds pregenerated signature list.
src/tasks/WasmAppBuilder/coreclr/InterpToNativeGenerator.cs Generates distinct PE thunks (extra hidden params + stack-walk sentinel) and maps ...p signatures.
src/tasks/WasmAppBuilder/coreclr/InternalCallSignatureCollector.cs New collector for InternalCall method signatures (for PE thunk generation).
src/coreclr/vm/wasm/helpers.cpp Adds PE thunk table + lookup; appends p to default-callconv signature keys; updates managed calli cookie invocation shape; adds thunk lookup for R2R→interp.
src/coreclr/vm/wasm/callhelpers-interp-to-managed.cpp Updates generated thunk implementations + table entries for ...p (PortableEntryPoint) signatures.
src/coreclr/vm/wasm/callhelpers-reverse.cpp Updates generated reverse thunks and some signatures/entry mappings.
src/coreclr/vm/prestub.cpp Adds PortableEntryPoint “complex” path that behaves prestub-like and can dispatch to R2R via InvokeManagedMethod.
src/coreclr/vm/precode_portable.hpp Adds PrefersInterpreterEntryPoint flag API to PortableEntryPoint.
src/coreclr/vm/precode_portable.cpp Updates HasNativeEntryPoint semantics and SetActualCode behavior with PrefersInterpreterEntryPoint.
src/coreclr/vm/method.cpp Uses R2R→interp thunk when available and sets PrefersInterpreterEntryPoint on new PortableEntryPoints.
src/coreclr/vm/jithelpers.cpp Updates WASM IL_Throw/IL_Rethrow/IL_ThrowExact wrappers to incorporate TransitionBlock/stack pointer logic.
src/coreclr/vm/interpexec.h Exposes InvokeManagedMethod declaration for new prestub path usage.
src/coreclr/vm/interpexec.cpp Adds helper-call wrappers for WASM portable-entrypoint calling convention; updates PortableEntryPoint/native-entrypoint selection logic.
src/coreclr/vm/callingconvention.h Extends WASM TransitionBlock storage with a unioned stack pointer field.
src/coreclr/vm/callhelpers.h Introduces TERMINATE_R2R_STACK_WALK sentinel for WASM stack walking.
src/coreclr/vm/frames.h Updates GCFrame ctor signature (bool → flags) and adjusts GCPROTECT macros.
src/coreclr/vm/frames.cpp Implements GCFrame flag-based scanning behavior.
src/coreclr/vm/gccover.cpp Updates GCFrame usage to pass GC flags.
src/coreclr/vm/ilstubcache.cpp Moves SetTemporaryEntryPoint call later in IL stub creation.
src/coreclr/vm/fcall.h Adjusts FCALL/HCALL signature macros for TARGET_WASM to include hidden params.
src/coreclr/vm/excep.cpp Plumbs TransitionBlock stack pointer into SoftwareExceptionFrame context on WASM.
src/coreclr/vm/eetwain.cpp Initializes TransitionBlock stack pointer for WASM funclet path.
src/coreclr/runtime/portable/AllocFast.cpp Updates RhpNewPtrArrayFast to match new WASM FCALL signature shape.

Comment on lines +56 to +58

foreach (var nestedType in type.GetNestedTypes())
ScanType(nestedType);
block.m_ReturnAddress = 0;
block.m_StackPointer = callersStackPointer;

IL_Throw_Impl(0, obj, (callersStackPointer == 0 || *(int*)callersStackPointer == TERMINATE_R2R_STACK_WALK) ? NULL : &block, 0);
Comment on lines +1317 to 1321
if (m_gcFlags != 0)
{
PromoteCarefully(fn, pRefs + i, sc, GC_CALL_INTERIOR | CHECK_APP_DOMAIN);
_ASSERTE(m_gcFlags & GC_CALL_INTERIOR);
PromoteCarefully(fn, pRefs + i, sc, m_gcFlags | CHECK_APP_DOMAIN);
}

// This is a lock free write. It can either be NULL or was already set to the same value.
_ASSERTE(!portableEntryPoint->HasNativeCode() || portableEntryPoint->_pActualCode == (void*)PCODEToPINSTR(actualCode));
// This is a lock free write. It can either be NULL, was already set to the same value, or be the interpreter entrypoint.
block.m_ReturnAddress = 0;
block.m_StackPointer = callersStackPointer;

IL_Rethrow_Impl(0, (callersStackPointer == 0 || *(int*)callersStackPointer == TERMINATE_R2R_STACK_WALK) ? NULL : &block, 0);
#ifdef TARGET_WASM
// A sentinel value to indicate to the stack walker that this frame is NOT R2R generated managed code,
// and it should look for the next Frame in the Frame chain to make further progress.
#define TERMINATE_R2R_STACK_WALK 1
block.m_ReturnAddress = 0;
block.m_StackPointer = callersStackPointer;

IL_ThrowExact_Impl(0, obj, (callersStackPointer == 0 || *(int*)callersStackPointer == TERMINATE_R2R_STACK_WALK) ? NULL : &block, 0);
Comment on lines +22 to +26
public void ScanAssembly(Assembly asm)
{
foreach (Type type in asm.GetTypes())
ScanType(type);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants